/*
 *  inject.cpp - part of LoadLib32
 *  Copyright (C) 2012  Dustin Escoffery
 *
 *  LoadLib32 is free software: you can redistribute it and/or
 *  modify it under the terms of the Lesser GNU General Public License
 *  as published by the Free Software Foundation, version 3 of the
 *  license.
 *
 *  LoadLib32 is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  Lesser GNU General Public License for more details.
 *
 *  You should have received a copy of the Lesser GNU General Public
 *  License along with LoadLib32.  If not, see:
 *      http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 *  CONTRIBUTORS:
 *      Dustin Escoffery
 */

#include "inject.h"
#include <windows.h>

// Makes a subroutine (x86) to call pFunc on lpArg, then return to Eip
void MakeStub(BYTE* buf, DWORD Eip, FARPROC pFunc, int n, LPVOID lpModules[])
{
   buf[0] = 0x68;                          // PUSH (Eip)
   memcpy(&buf[1], &Eip, 4);
   buf[5] = 0x9C;                          // PUSHFD
   buf[6] = 0x60;                          // PUSHAD
   int off = 7;
   for (int m = 0; m < n; ++m)
   {
      buf[off++] = 0x68;                   // PUSH (lpArg)
      memcpy(&buf[off], &lpModules[m], 4);
      off += 4;
      buf[off++] = 0xB8;                   // MOV EAX, (pFunc)
      memcpy(&buf[off], &pFunc, 4);
      off += 4;
      buf[off++] = 0xFF;                   // CALL EAX
      buf[off++] = 0xD0;
   }
   buf[off++] = 0x61;                      // POPAD
   buf[off++] = 0x9D;                      // POPFD
   buf[off++] = 0xC3;                      // RET
}

// Gets hThread's instruction pointer
DWORD GetInstruction(HANDLE hThread)
{
   CONTEXT ctx;
   ctx.ContextFlags = CONTEXT_CONTROL;
   GetThreadContext(hThread, &ctx);
   return ctx.Eip;
}

// Sets hThread's instruction pointer
void SetInstruction(HANDLE hThread, DWORD Eip)
{
   CONTEXT ctx;
   GetThreadContext(hThread, &ctx);
   ctx.Eip = Eip;
   SetThreadContext(hThread, &ctx);
}

// Injects LoadLibrary(module) subroutine into process pi
void InjectLibs(PROCESS_INFORMATION pi, int count, char* modules[])
{
   if (count == 0) return;

   // Open process for writing
   HANDLE hProcess = OpenProcess(
      (PROCESS_VM_WRITE | PROCESS_VM_OPERATION), 0, pi.dwProcessId);
   DWORD Eip = GetInstruction(pi.hThread);

   LPVOID *lpModules = new LPVOID[count];
   for (int m = 0; m < count; ++m)
   {
      // Write module name to process
      char* sModule = modules[m];
      lpModules[m] = VirtualAllocEx(
         hProcess, NULL, strlen(sModule), MEM_COMMIT, PAGE_READWRITE);
      WriteProcessMemory(hProcess, lpModules[m], sModule, strlen(sModule), 0);
   }

   // Write load library procedure (stub) to process
   const int STUB_LEN = 10 + 12 * count;
   LPVOID lpStub = VirtualAllocEx(
      hProcess, NULL, STUB_LEN, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
   FARPROC pfnLoadLib = GetProcAddress(
      GetModuleHandle("kernel32.dll"), "LoadLibraryA");
   BYTE *bufStub = new BYTE[STUB_LEN];
   MakeStub(bufStub, Eip, pfnLoadLib, count, lpModules);
   WriteProcessMemory(hProcess, lpStub, bufStub, STUB_LEN, NULL);
   delete lpModules;

   // Redirect process, close handle
   SetInstruction(pi.hThread, (DWORD)lpStub);
   CloseHandle(hProcess);
}
